package com.bootdo.common.utils;

import com.bootdo.common.utils.MD5Utils;
import com.bootdo.common.utils.PayCommonUtil;
import com.bootdo.wx.domain.SetWechatDO;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.apache.velocity.texen.util.PropertiesUtil;
import org.jdom2.JDOMException;
import org.springframework.stereotype.Service;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.text.SimpleDateFormat;
import java.util.*;
/**
 * Created by HP on 2019/7/13.
 */
public class WeChatPayUtils {

    private static final String URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    /*private static final String APP_ID = "wx0fd5a1a2a25623da";
    private static final String MCH_ID = "1512710461";
    private static final String TRADE_TYPE = "JSAPI";
    private static final String SIGN_TYPE = "MD5";
    private static final String CHARSET = "UTF-8";

    private static String Key = "we8ewbk02fz4xbrnzq2up751ymy5ds32";*/

    /**
     * @param args
     */
    /*public static void main(String[] args) {
//        System.out.println(MD5Util.getRandomStringByLength(32));
//        System.out.println(MD5Util.getRandomStringByLength(32).length());
        SortedMap<String ,String> map = new TreeMap<>();
        map.put("body", "套餐名称"); //商品描述  必
        //map.put("attach", "套餐附加信息"); //商品详情  非
        map.put("out_trade_no", "20879403372943360"); //商户订单号  必
        map.put("total_fee", "1"); //总金额  必
        map.put("spbill_create_ip", "182.119.183.6"); //终端ip  用户端ip  必
        WeixinpayService wxService = new WeixinpayService();
        WeixinOrder resultMap =wxService.getOrderSignature(map);
    }*/

    /**
     * 微信支付签名算法sign
     * @param characterEncoding
     * @param parameters
     * @return
     */
    public static String createSign(String characterEncoding,SortedMap<Object,Object> parameters,SetWechatDO setWechatDO){
        StringBuffer sb = new StringBuffer();
        Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序（升序）
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            Object v = entry.getValue();
            if(null != v && !"".equals(v)
                    && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        sb.append("key=" + setWechatDO.getKey());
        System.out.println("拼接信息:"+sb);
        String sign = MD5Utils.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        return sign;
    }



/**
 * AlipaySignature.rsaSign(order.getMapString(), APP_PRIVATE_KEY, CHARSET, SIGN_TYPE); 签名
 * AlipaySignature.rsaCheckV1()验签
 */
    /**
     * @param map
     * @return
     */
    public static Map<String,Object> signature(SortedMap map,SetWechatDO setWechatDO) {
        String sign =  createSign(setWechatDO.getCharset(),map,setWechatDO);
        String xml ="<xml>\n" +
                "   <appid>"+map.get("appid")+"</appid>\n" +
                "   <attach>"+map.get("attach")+"</attach>" +
                "   <body>"+map.get("body")+"</body>" +
                "   <mch_id>"+map.get("mch_id")+"</mch_id>" +
                "   <nonce_str>"+map.get("nonce_str")+"</nonce_str>" +
                "   <notify_url>"+map.get("notify_url")+"</notify_url>" +
                "   <openid>"+map.get("openid")+"</openid>" +
                "   <out_trade_no>"+map.get("out_trade_no")+"</out_trade_no>" +
                "   <spbill_create_ip>"+map.get("spbill_create_ip")+"</spbill_create_ip>" +
                "   <time_start>"+map.get("time_start")+"</time_start>" +
                "   <total_fee>"+map.get("total_fee")+"</total_fee>" +
                "   <trade_type>"+map.get("trade_type")+"</trade_type>" +
                "   <sign>"+sign+"</sign>" +
                "</xml>";
        String result = PayCommonUtil.httpsRequest(
                URL, "POST", xml);
        Map<String, String> resultMap = null;
        try {
            resultMap = PayCommonUtil.doXMLParse(result);
        } catch (JDOMException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        SortedMap<Object, Object> parameterMap = new TreeMap<Object, Object>();

        parameterMap.put("appId", setWechatDO.getAppId());
        parameterMap.put("timeStamp", System.currentTimeMillis()/1000);
        parameterMap.put("nonceStr", resultMap.get("nonce_str"));
        parameterMap.put("signType", "MD5");
        parameterMap.put("package", "prepay_id="+resultMap.get("prepay_id"));
        String sign2 = createSign(setWechatDO.getCharset(), parameterMap,setWechatDO);
        //parameterMap.put("sign", sign2);
        //jsonObject.put("parameterMap",parameterMap);
        Map<String,Object> map2 = new HashMap<String,Object>();
        map2.put("appId", setWechatDO.getAppId());
        map2.put("partnerId",setWechatDO.getMchId());
        map2.put("prepayId",parameterMap.get("package").toString());
        map2.put("nonceStr", parameterMap.get("nonceStr").toString());
        map2.put("timeStamp", parameterMap.get("timeStamp").toString());
        map2.put("sign", sign2);
        System.out.println("返回前台信息： " + (map2.toString()));
        return map2 ;
    }


    public static Map<String,Object> getOrderSignature(SortedMap map,SetWechatDO setWechatDO) {
        //WeixinOrder map = new WeixinOrder(APP_ID,MCH_ID,Json.toJson(order,JsonFormat.compact()),SIGN_TYPE) ;//new WeixinOrder(APP_ID, Json.toJson(order, JsonFormat.compact()));
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
        map.put("nonce_str",MD5Utils.getRandomStringByLength(32));
        //map.setNonce_str(MD5Util.getRandomStringByLength(32));
        map.put("time_start",df.format(new Date()));
        //map.setTime_start(df.format(new Date()));
        //map.setNotifyUrl("https://www.meipinjie.net/meipin/open/api/pay/weixinpayNotify");
        map.put("appid", setWechatDO.getAppId()); //应用ID  必
        map.put("mch_id", setWechatDO.getMchId()); //商户号  必
        //map.put("sign_type", "MD5"); //签名类型默认MD5
        //.put("notify_url", order.getTotalAmount()); //通知地址 回调url  必
        map.put("trade_type", setWechatDO.getTradeType()); //交易类型  APP 必
        //map.put("time_start", order.getTotalAmount()); //交易开始时间  必
        //signMap.put("time_expire", order.getTotalAmount()); //交易结束时间    大于5分钟
        return signature(map,setWechatDO);
    }



    //退款所需
    private  static int socketTimeout = 10000;// 连接超时时间，默认10秒
    private  static int connectTimeout = 30000;// 传输超时时间，默认30秒
    private  static RequestConfig requestConfig;// 请求器的配置
    private  static CloseableHttpClient httpClient;// HTTP请求器

    /**
     * 加载证书
     *
     */
    private static void initCert(SetWechatDO setWechatDO) throws Exception {
        // 证书密码，默认为商户ID
        String key = setWechatDO.getMchId();
        // 商户证书的路径, 读取本机存放的PKCS12证书文件
        /*String path = "/api/wxCert.p12";    这个写绝对路径
        FileInputStream instream = new FileInputStream(new File(path));*/
        InputStream instream = PropertiesUtil.class.getResourceAsStream("/public/api/hyWxCert.p12");

        // 指定读取证书格式为PKCS12
        KeyStore keyStore = KeyStore.getInstance("PKCS12");

        try {
            // 指定PKCS12的密码(商户ID)
            keyStore.load(instream, key.toCharArray());
        } finally {
            instream.close();
        }

        SSLContext sslcontext = SSLContexts.custom().loadKeyMaterial(keyStore, key.toCharArray()).build();

        // 指定TLS版本
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, new String[] { "TLSv1" }, null,SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        // 设置httpclient的SSLSocketFactory
        httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
    }


    /**
     * 通过Https往API post xml数据
     * @param url  API地址
     * @param xmlObj   要提交的XML数据对象
     * @return
     */
    public static String postData(String url, String xmlObj,SetWechatDO setWechatDO) {
        // 加载证书
        try {
            initCert(setWechatDO);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String result = null;
        HttpPost httpPost = new HttpPost(url);
        // 得指明使用UTF-8编码，否则到API服务器XML的中文不能被成功识别
        StringEntity postEntity = new StringEntity(xmlObj, "UTF-8");
        httpPost.addHeader("Content-Type", "text/xml");
        httpPost.setEntity(postEntity);
        // 根据默认超时限制初始化requestConfig
        requestConfig = RequestConfig.custom()
                .setSocketTimeout(socketTimeout)
                .setConnectTimeout(connectTimeout)
                .build();
        // 设置请求器的配置
        httpPost.setConfig(requestConfig);
        try {
            HttpResponse response = null;
            try {
                response = httpClient.execute(httpPost);
            }  catch (IOException e) {
                e.printStackTrace();
            }
            HttpEntity entity = response.getEntity();
            try {
                result = EntityUtils.toString(entity, "UTF-8");
            }  catch (IOException e) {
                e.printStackTrace();
            }
        } finally {
            httpPost.abort();
        }
        return result;
    }

    private static String getRandomStringByLength(int length) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }




}
